package com.jahe.learn.netty4.websocket;

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketCloseStatus;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 服务器端检测连接通道读写超时，关闭连接。
 * @author: jahe.lai
 * @create: 2019-12-25 17:11
 */
public class HeartBeatHandler extends ChannelInboundHandlerAdapter {

    protected static Logger logger = LoggerFactory.getLogger(HeartBeatHandler.class);

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent)evt;
            // 设置了读取客户端数据的空闲时间。时间到了发送一条Pong消息给客户端。如果不回应。读写都空闲的时间到了就关闭连接。
            if (event.state() == IdleState.READER_IDLE) {
                logger.warn("{} 读超时。Client长时间未发消息过来。", ctx.channel().remoteAddress());
                if (ctx.channel().isActive()) {
                    ctx.channel().writeAndFlush(new PongWebSocketFrame(Unpooled.copiedBuffer("TIMEOUT".getBytes())));
                }
                return;
            }

            String eventType = null;
            switch (event.state()) {
                case ALL_IDLE:
                    eventType = "读写都空闲";
                    break;
                case READER_IDLE:
                    eventType = "读空闲";
                    break;
                case WRITER_IDLE:
                    eventType = "写空闲";
                    break;
            }
            // websocket的关闭协议
            ctx.channel().writeAndFlush(new CloseWebSocketFrame(WebSocketCloseStatus.NORMAL_CLOSURE, eventType));
            ctx.channel().close();
            logger.warn("{} {}。关闭连接。", ctx.channel().remoteAddress(), eventType);
        }
    }
}
